namespace ds
{
    const DEFAULT_BASE = 17;

    export class SimplePolynomialHash
    {
        base: number;

        /**
         * @param {number} [base] - Base number that is used to create the polynomial.
         */
        constructor(base = DEFAULT_BASE)
        {
            this.base = base;
        }

        /**
         * Function that creates hash representation of the word.
         *
         * Time complexity: O(word.length).
         *
         * @assumption: This version of the function  doesn't use modulo operator.
         * Thus it may produce number overflows by generating numbers that are
         * bigger than Number.MAX_SAFE_INTEGER. This function is mentioned here
         * for simplicity and LEARNING reasons.
         *
         * @param {string} word - String that needs to be hashed.
         * @return {number}
         */
        hash(word)
        {
            let hash = 0;
            for (let charIndex = 0; charIndex < word.length; charIndex += 1)
            {
                hash += word.charCodeAt(charIndex) * (this.base ** charIndex);
            }

            return hash;
        }

        /**
         * Function that creates hash representation of the word
         * based on previous word (shifted by one character left) hash value.
         *
         * Recalculates the hash representation of a word so that it isn't
         * necessary to traverse the whole word again.
         *
         * Time complexity: O(1).
         *
         * @assumption: This function doesn't use modulo operator and thus is not safe since
         * it may deal with numbers that are bigger than Number.MAX_SAFE_INTEGER. This
         * function is mentioned here for simplicity and LEARNING reasons.
         *
         * @param {number} prevHash
         * @param {string} prevWord
         * @param {string} newWord
         * @return {number}
         */
        roll(prevHash, prevWord, newWord)
        {
            let hash = prevHash;

            const prevValue = prevWord.charCodeAt(0);
            const newValue = newWord.charCodeAt(newWord.length - 1);

            hash -= prevValue;
            hash /= this.base;
            hash += newValue * (this.base ** (newWord.length - 1));

            return hash;
        }
    }

}